#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../../test.h"

#include "trilogy/error.h"
#include "trilogy/protocol.h"

static const char user[] = "root";

static const char pass[] = "testing";

TEST test_build_auth_packet_native()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;

    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "kw6C.]j}Wy|%<@jx>gml";

    err = trilogy_build_auth_packet(&builder, user, NULL, 0, NULL, 45, "mysql_native_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {0x3c, 0x00, 0x00, 0x01, 0x00, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d,
                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6f,
                                       0x74, 0x00, 0x00, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69,
                                       0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));
    ASSERT_EQ(sizeof(expected), buff.len);

    trilogy_buffer_free(&buff);

    PASS();
}

TEST test_build_auth_packet_sha2()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;

    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "kw6C.]j}Wy|%<@jx>gml";

    err = trilogy_build_auth_packet(&builder, user, NULL, 0, NULL, 45, "caching_sha2_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {0x3c, 0x00, 0x00, 0x01, 0x00, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d,
                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6f,
                                       0x74, 0x00, 0x00, 0x63, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x68,
                                       0x61, 0x32, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));
    ASSERT_EQ(sizeof(expected), buff.len);

    trilogy_buffer_free(&buff);

    PASS();
}

TEST test_build_auth_packet_native_with_pass()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;
    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "I/JiR>}{tU-{G3e$\"{hx";

    err = trilogy_build_auth_packet(&builder, user, pass, strlen(pass), NULL, 45, "mysql_native_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {
        0x50, 0x00, 0x00, 0x01, 0x00, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xdd, 0x50, 0x11, 0x25, 0x22, 0x39, 0x2e, 0x81, 0xd0,
        0x48, 0x7c, 0x68, 0x95, 0x08, 0x67, 0x15, 0xf2, 0x93, 0xe7, 0x34, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f,
        0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));
    ASSERT_EQ(sizeof(expected), buff.len);

    trilogy_buffer_free(&buff);

    PASS();
}

TEST test_build_auth_packet_sha2_with_pass()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;
    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "I/JiR>}{tU-{G3e$\"{hx";

    err = trilogy_build_auth_packet(&builder, user, pass, strlen(pass), NULL, 45, "caching_sha2_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {
        0x5c, 0x00, 0x00, 0x01, 0x00, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x20, 0xfc, 0x30, 0xeb, 0x5a, 0x4b, 0x6d,
        0x62, 0x82, 0x52, 0x0d, 0x8a, 0x78, 0x7b, 0xd3, 0xcf, 0xc8, 0x46, 0xb8, 0x7f, 0x2e, 0x31, 0x14,
        0x67, 0x57, 0x84, 0xee, 0xc6, 0x5e, 0x25, 0x69, 0x63, 0xea, 0x63, 0x61, 0x63, 0x68, 0x69, 0x6e,
        0x67, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_EQ(sizeof(expected), buff.len);
    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));

    trilogy_buffer_free(&buff);

    PASS();
}

TEST test_build_auth_packet_native_with_database()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;
    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "kw6C.]j}Wy|%<@jx>gml";

    err = trilogy_build_auth_packet(&builder, user, NULL, 0, "test", 45, "mysql_native_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {
        0x41, 0x00, 0x00, 0x01, 0x08, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x72, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x6e,
        0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));
    ASSERT_EQ(sizeof(expected), buff.len);

    trilogy_buffer_free(&buff);

    PASS();
}

TEST test_build_auth_packet_sha2_with_database()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;
    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "kw6C.]j}Wy|%<@jx>gml";

    err = trilogy_build_auth_packet(&builder, user, NULL, 0, "test", 45, "caching_sha2_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {
        0x41, 0x00, 0x00, 0x01, 0x08, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x72, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x00, 0x63, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67,
        0x5f, 0x73, 0x68, 0x61, 0x32, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));
    ASSERT_EQ(sizeof(expected), buff.len);

    trilogy_buffer_free(&buff);

    PASS();
}

TEST test_build_auth_packet_native_with_pass_and_database()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;
    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "I/JiR>}{tU-{G3e$\"{hx";

    err = trilogy_build_auth_packet(&builder, user, pass, strlen(pass), "test", 45, "mysql_native_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {
        0x55, 0x00, 0x00, 0x01, 0x08, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xdd, 0x50, 0x11, 0x25, 0x22, 0x39, 0x2e, 0x81, 0xd0, 0x48, 0x7c, 0x68,
        0x95, 0x08, 0x67, 0x15, 0xf2, 0x93, 0xe7, 0x34, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6d, 0x79, 0x73, 0x71, 0x6c,
        0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));
    ASSERT_EQ(sizeof(expected), buff.len);

    trilogy_buffer_free(&buff);

    PASS();
}

TEST test_build_auth_packet_sha2_with_pass_and_database()
{
    trilogy_builder_t builder;
    trilogy_buffer_t buff;
    int err = trilogy_buffer_init(&buff, 1);
    ASSERT_OK(err);

    err = trilogy_builder_init(&builder, &buff, 1);
    ASSERT_OK(err);

    static const char scramble[] = "I/JiR>}{tU-{G3e$\"{hx";

    err = trilogy_build_auth_packet(&builder, user, pass, strlen(pass), "test", 45, "caching_sha2_password", scramble, 0);
    ASSERT_OK(err);

    static const uint8_t expected[] = {
        0x61, 0x00, 0x00, 0x01, 0x08, 0xa2, 0x88, 0x01, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x20, 0xfc, 0x30, 0xeb, 0x5a, 0x4b, 0x6d, 0x62, 0x82, 0x52,
        0x0d, 0x8a, 0x78, 0x7b, 0xd3, 0xcf, 0xc8, 0x46, 0xb8, 0x7f, 0x2e, 0x31, 0x14, 0x67, 0x57, 0x84, 0xee,
        0xc6, 0x5e, 0x25, 0x69, 0x63, 0xea, 0x74, 0x65, 0x73, 0x74, 0x00, 0x63, 0x61, 0x63, 0x68, 0x69, 0x6e,
        0x67, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};

    ASSERT_MEM_EQ(expected, buff.buff, sizeof(expected));
    ASSERT_EQ(sizeof(expected), buff.len);

    trilogy_buffer_free(&buff);

    PASS();
}

int build_auth_packet_test()
{
    RUN_TEST(test_build_auth_packet_native);
    RUN_TEST(test_build_auth_packet_sha2);
    RUN_TEST(test_build_auth_packet_native_with_pass);
    RUN_TEST(test_build_auth_packet_sha2_with_pass);
    RUN_TEST(test_build_auth_packet_native_with_database);
    RUN_TEST(test_build_auth_packet_sha2_with_database);
    RUN_TEST(test_build_auth_packet_native_with_pass_and_database);
    RUN_TEST(test_build_auth_packet_sha2_with_pass_and_database);
    return 0;
}
